@rubytech/create-realagent 1.0.858 → 1.0.859
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/cdp-port-no-silent-fallback.test.js +53 -0
- package/dist/index.js +52 -16
- package/package.json +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +20 -10
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/cloudflare/references/manual-setup.md +1 -1
- package/payload/platform/scripts/test-laptop-vnc-boot.sh +8 -1
- package/payload/platform/scripts/vnc.sh +34 -28
- package/payload/server/chunk-22LK7D5R.js +1612 -0
- package/payload/server/chunk-2Q2S52GB.js +10906 -0
- package/payload/server/client-pool-3BCJTPPA.js +34 -0
- package/payload/server/maxy-edge.js +33 -5
- package/payload/server/public/assets/{admin-CZpefPcA.js → admin-BumnnEDn.js} +60 -60
- package/payload/server/public/index.html +1 -1
- package/payload/server/server.js +197 -129
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Task 959 — structural gate against the recurrence-class
|
|
2
|
+
// silent-fallback-masks-root-cause violation. The four runtime sites that
|
|
3
|
+
// previously substituted `9222 + offset` for a missing brand.json.cdpPort
|
|
4
|
+
// (paths.ts, admin/mcp/index.ts, vnc.sh, test-laptop-vnc-boot.sh) plus the
|
|
5
|
+
// installer-side brand stamp at packages/create-maxy/src/index.ts have all
|
|
6
|
+
// been swept to loud-fail. This test asserts the three greps from criterion
|
|
7
|
+
// 2 of the task brief return zero matches; reintroducing any silent fallback
|
|
8
|
+
// fails CI immediately.
|
|
9
|
+
//
|
|
10
|
+
// Compiles to dist/__tests__/cdp-port-no-silent-fallback.test.js and runs
|
|
11
|
+
// via `node --test 'dist/__tests__/*.test.js'` per package.json's test
|
|
12
|
+
// script. Greps run via `git grep` rooted at the repo top-level (resolved
|
|
13
|
+
// relative to dist/__tests__/'s known offset) so the test is invariant to
|
|
14
|
+
// the caller's cwd.
|
|
15
|
+
import test from "node:test";
|
|
16
|
+
import assert from "node:assert/strict";
|
|
17
|
+
import { spawnSync } from "node:child_process";
|
|
18
|
+
import { resolve } from "node:path";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
const SELF_DIR = fileURLToPath(new URL(".", import.meta.url));
|
|
21
|
+
// dist/__tests__/ → repo root is four levels up
|
|
22
|
+
// (packages/create-maxy/dist/__tests__ → packages/create-maxy → packages → repo).
|
|
23
|
+
const REPO_ROOT = resolve(SELF_DIR, "..", "..", "..", "..");
|
|
24
|
+
function grepReturns(pattern, includes) {
|
|
25
|
+
const args = ["-RnE", pattern];
|
|
26
|
+
for (const inc of includes)
|
|
27
|
+
args.push(`--include=${inc}`);
|
|
28
|
+
args.push("platform/", "packages/");
|
|
29
|
+
// Exclude this test file (it embeds the patterns as string literals,
|
|
30
|
+
// which would otherwise self-match) and exclude the gitignored payload
|
|
31
|
+
// mirror generated by `npm run bundle`.
|
|
32
|
+
args.push("--exclude-dir=payload");
|
|
33
|
+
args.push("--exclude=cdp-port-no-silent-fallback.test.*");
|
|
34
|
+
const out = spawnSync("grep", args, { cwd: REPO_ROOT, encoding: "utf8" });
|
|
35
|
+
// grep exit 1 = no matches (success for this test); exit 0 = matches found
|
|
36
|
+
// (failure); exit 2 = grep error (test infrastructure fault).
|
|
37
|
+
if (out.status !== 0 && out.status !== 1) {
|
|
38
|
+
throw new Error(`grep error (status=${out.status}): ${out.stderr}`);
|
|
39
|
+
}
|
|
40
|
+
return (out.stdout ?? "").trim();
|
|
41
|
+
}
|
|
42
|
+
test("Task 959 grep 1: no `9222 + offset` arithmetic in source files", () => {
|
|
43
|
+
const matches = grepReturns("9222\\s*\\+\\s*\\w*offset", ["*.ts", "*.tsx", "*.sh"]);
|
|
44
|
+
assert.equal(matches, "", `silent-fallback regression — '9222 + offset' arithmetic reintroduced:\n${matches}`);
|
|
45
|
+
});
|
|
46
|
+
test("Task 959 grep 2: no jq `cdpPort // 9222` fallback in shell or TS", () => {
|
|
47
|
+
const matches = grepReturns("cdpPort\\s*//\\s*9222", ["*.sh", "*.ts"]);
|
|
48
|
+
assert.equal(matches, "", `silent-fallback regression — jq cdpPort // 9222 fallback reintroduced:\n${matches}`);
|
|
49
|
+
});
|
|
50
|
+
test("Task 959 grep 3: no `?? 9222` or `|| 9222` nullish-coalesce in TS", () => {
|
|
51
|
+
const matches = grepReturns("\\?\\?\\s*9222|\\|\\|\\s*9222", ["*.ts"]);
|
|
52
|
+
assert.equal(matches, "", `silent-fallback regression — '?? 9222' or '|| 9222' coalesce reintroduced:\n${matches}`);
|
|
53
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -1931,12 +1931,36 @@ function setupVncViewer() {
|
|
|
1931
1931
|
} catch (e) { /* swallow */ }
|
|
1932
1932
|
}
|
|
1933
1933
|
|
|
1934
|
+
// Layer-6 beacon (Task 958): emit event=rfb-connected and
|
|
1935
|
+
// event=rfb-error to the operator-grep lifecycle endpoint so
|
|
1936
|
+
// server.log shows the noVNC outcome alongside [setup-tunnel] /
|
|
1937
|
+
// [cloudflare-setup] / [device-url:click] / [http] / [websockify].
|
|
1938
|
+
// Same-origin POST works whether the iframe is parented by the
|
|
1939
|
+
// React BrowserViewer or by vnc-popout.html.
|
|
1940
|
+
function reportBrowserViewerEvent(event, fields) {
|
|
1941
|
+
try {
|
|
1942
|
+
var body = JSON.stringify(Object.assign(
|
|
1943
|
+
{ event: event, surface: 'iframe' },
|
|
1944
|
+
fields || {},
|
|
1945
|
+
));
|
|
1946
|
+
fetch('/api/admin/browser-iframe/event', {
|
|
1947
|
+
method: 'POST',
|
|
1948
|
+
credentials: 'same-origin',
|
|
1949
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1950
|
+
body: body,
|
|
1951
|
+
keepalive: true,
|
|
1952
|
+
}).catch(function() { /* swallow */ });
|
|
1953
|
+
} catch (e) { /* swallow */ }
|
|
1954
|
+
}
|
|
1955
|
+
var connectStartedAt = 0;
|
|
1956
|
+
|
|
1934
1957
|
function connect() {
|
|
1935
1958
|
status.classList.remove('hidden');
|
|
1936
1959
|
status.querySelector('.status-spinner').style.display = '';
|
|
1937
1960
|
status.querySelector('div:nth-child(2)').textContent =
|
|
1938
1961
|
retryCount > 0 ? 'Reconnecting… (' + retryCount + ')' : 'Connecting to browser…';
|
|
1939
1962
|
status.querySelector('.status-reason').textContent = '';
|
|
1963
|
+
connectStartedAt = Date.now();
|
|
1940
1964
|
|
|
1941
1965
|
const rfb = new RFB(screen, wsUrl);
|
|
1942
1966
|
rfb.scaleViewport = true;
|
|
@@ -1947,6 +1971,9 @@ function setupVncViewer() {
|
|
|
1947
1971
|
rfb.addEventListener('connect', () => {
|
|
1948
1972
|
status.classList.add('hidden');
|
|
1949
1973
|
retryCount = 0;
|
|
1974
|
+
reportBrowserViewerEvent('rfb-connected', {
|
|
1975
|
+
durationMs: Date.now() - connectStartedAt,
|
|
1976
|
+
});
|
|
1950
1977
|
});
|
|
1951
1978
|
|
|
1952
1979
|
rfb.addEventListener('disconnect', (e) => {
|
|
@@ -1954,6 +1981,11 @@ function setupVncViewer() {
|
|
|
1954
1981
|
const detail = e.detail || {};
|
|
1955
1982
|
const reason = detail.reason || (detail.clean === false ? 'Connection refused' : '');
|
|
1956
1983
|
reportClientEvent('disconnect', reason || (detail.clean === false ? 'unclean-close' : 'normal'));
|
|
1984
|
+
reportBrowserViewerEvent('rfb-error', {
|
|
1985
|
+
durationMs: Date.now() - connectStartedAt,
|
|
1986
|
+
errorCode: detail.clean === false ? 'unclean-close' : 'normal',
|
|
1987
|
+
message: reason || '',
|
|
1988
|
+
});
|
|
1957
1989
|
const reasonEl = status.querySelector('.status-reason');
|
|
1958
1990
|
if (retryCount < MAX_RETRIES) {
|
|
1959
1991
|
retryCount++;
|
|
@@ -2458,22 +2490,26 @@ function installService() {
|
|
|
2458
2490
|
// Per-brand X display (Task 553). Same value used for the edge unit's
|
|
2459
2491
|
// DISPLAY env (stamped via __VNC_DISPLAY__ a few lines down) so the main
|
|
2460
2492
|
// brand service and the edge service agree on which display Chromium runs.
|
|
2461
|
-
|
|
2462
|
-
//
|
|
2463
|
-
//
|
|
2464
|
-
//
|
|
2465
|
-
//
|
|
2466
|
-
//
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2493
|
+
// Task 924 + 959 — brand.json (BRAND) is the single source of truth for
|
|
2494
|
+
// these fields at install time. The vncDisplay-derived offset rule lives
|
|
2495
|
+
// in the brand-creation tooling; at this point in the installer BRAND
|
|
2496
|
+
// already represents a parsed, validated brand manifest, and any missing
|
|
2497
|
+
// field is a brand-publish defect. Loud-fail rather than silently
|
|
2498
|
+
// substituting an offset (silent-fallback-masks-root-cause recurrence).
|
|
2499
|
+
if (typeof BRAND.vncDisplay !== "number") {
|
|
2500
|
+
console.error(`[create-maxy] error reason=cdp-port-unresolved brand=${BRAND.configDir} field=vncDisplay`);
|
|
2501
|
+
throw new Error(`brand.json missing required field: vncDisplay`);
|
|
2502
|
+
}
|
|
2503
|
+
const VNC_DISPLAY = BRAND.vncDisplay;
|
|
2504
|
+
for (const field of ["rfbPort", "websockifyPort", "cdpPort"]) {
|
|
2505
|
+
if (typeof BRAND[field] !== "number") {
|
|
2506
|
+
console.error(`[create-maxy] error reason=cdp-port-unresolved brand=${BRAND.configDir} field=${field}`);
|
|
2507
|
+
throw new Error(`brand.json missing required field: ${field}`);
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
const RFB_PORT = BRAND.rfbPort;
|
|
2511
|
+
const WEBSOCKIFY_PORT_BRAND = BRAND.websockifyPort;
|
|
2512
|
+
const CDP_PORT_BRAND = BRAND.cdpPort;
|
|
2477
2513
|
// Task 924/938 pre-flight — refuse to write service files if any of the
|
|
2478
2514
|
// three brand-scoped ports is already held by a process that is NOT this
|
|
2479
2515
|
// brand's own on-demand browser nor a peer brand's edge stack.
|
package/package.json
CHANGED
|
@@ -50,20 +50,30 @@ function resolveBrandConfig() {
|
|
|
50
50
|
if (!brand.productName) {
|
|
51
51
|
throw new Error(`brand.json at ${brandPath} is missing the productName field`);
|
|
52
52
|
}
|
|
53
|
-
// Task 924 —
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
const
|
|
53
|
+
// Task 924 + 959 — brand.json is the single source of truth for the
|
|
54
|
+
// four brand-scoped port fields. An admin MCP probe must see the exact
|
|
55
|
+
// same numbers the rest of the platform binds; silent vncDisplay-derived
|
|
56
|
+
// fallback was a recurrence-class silent-fallback-masks-root-cause
|
|
57
|
+
// violation (Task 959) and is now loud-fail.
|
|
58
|
+
const brandLabel = String(brand.configDir).replace(/^\./, "");
|
|
59
|
+
if (typeof brand.vncDisplay !== "number") {
|
|
60
|
+
console.error(`[mcp:admin] error reason=cdp-port-unresolved brand=${brandLabel} path=${brandPath} field=vncDisplay json_keys=${Object.keys(brand).join(",")}`);
|
|
61
|
+
throw new Error(`brand.json at ${brandPath} missing required field: vncDisplay`);
|
|
62
|
+
}
|
|
63
|
+
for (const field of ["rfbPort", "websockifyPort", "cdpPort"]) {
|
|
64
|
+
if (typeof brand[field] !== "number") {
|
|
65
|
+
console.error(`[mcp:admin] error reason=cdp-port-unresolved brand=${brandLabel} path=${brandPath} field=${field} json_keys=${Object.keys(brand).join(",")}`);
|
|
66
|
+
throw new Error(`brand.json at ${brandPath} missing required field: ${field}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
59
69
|
return {
|
|
60
70
|
configDir: brand.configDir,
|
|
61
71
|
productName: brand.productName,
|
|
62
72
|
commercialMode: brand.commercialMode === true,
|
|
63
|
-
vncDisplay,
|
|
64
|
-
rfbPort:
|
|
65
|
-
websockifyPort:
|
|
66
|
-
cdpPort:
|
|
73
|
+
vncDisplay: brand.vncDisplay,
|
|
74
|
+
rfbPort: brand.rfbPort,
|
|
75
|
+
websockifyPort: brand.websockifyPort,
|
|
76
|
+
cdpPort: brand.cdpPort,
|
|
67
77
|
};
|
|
68
78
|
}
|
|
69
79
|
catch (err) {
|